import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.net.URL;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

//import javax.xml.parsers.DocumentBuilder;
//import javax.xml.parsers.DocumentBuilderFactory;

//import org.w3c.dom.Document;
//import org.w3c.dom.Element;
//import org.w3c.dom.Node;
//import org.w3c.dom.NodeList;

class PublicationListCitationFactory extends CitationFactory {

	private String xPath = "";
	private String prefix = "";
	private String namespaceURI = "";
	private String PublicationType[];
	
	
	public void setPeerReviewedXPath(String xpath) {
		this.xPath = xpath;
	}
	
	public void setXMLPrefix(String prefix) {
		this.prefix = prefix;
	}
	
	public void setXMLNamespaceURI(String uri) {
		this.namespaceURI = uri;
	}
	
	public void setPublicationType(String[] type) {
		this.PublicationType = type;
	}
	
	public String produce(String[] objIds) throws MP2Exception {
		
		if (this.PublicationType[2].trim().equals("")) {
			return super.produce(objIds);
		} else if (this.PublicationType[2].trim().equalsIgnoreCase("all")) {
			return super.produce(objIds);
		} 
		
		//if (OutputFile.equals(""))			
		try {
			this.createOutputFile();
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.UnableToCreateOutputFileErr);
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
			throw mp2;
		}
		/*
		try {
			this.readFromConfig();
		} catch (Exception e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.ReadingConfFileErr);
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
			throw mp2;
		}
		*/
		XMLProcessor proxml = new XMLProcessor();
		try {
			TempXML = this.createTempFile(""+System.currentTimeMillis(), "xml");
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.CreateTempFileErr);
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
			throw mp2;
		}
		
		try {
			TempOutFile = this.createTempFile(""+System.currentTimeMillis(), Suffix);
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.CreateTempFileErr);
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
			throw mp2;
		}
		for (int i = 0; i < Array.getLength(objIds); i++) {			
			try {
				this.getXMLFile((String) objIds[i], TempXML);
				Configuration conf = new Configuration();
				conf.fileToRead = TempXML; 
				
				if (this.PublicationType[2].trim().equalsIgnoreCase("yes")) {
					try {
						String nodeValue;
						if ((this.prefix == "") || (this.namespaceURI == ""))
							nodeValue = conf.getNodeViaPath(this.xPath);
						else 
							nodeValue = conf.getNodeViaPath(this.xPath, this.prefix, this.namespaceURI);
						if ((nodeValue == null) || (!nodeValue.equalsIgnoreCase("yes")))
							continue;
					} catch (Exception e) {
						MP2Exception mp2 = new MP2Exception();
						mp2.setMessage("Error Received When Getting Item 'Yes' using XPATH.");
						System.err.println(mp2.sendMessage());
						e.printStackTrace();
						throw mp2;
					}
				} else if (this.PublicationType[2].trim().equalsIgnoreCase("no")) {
					try {
						String nodeValue;
						if ((this.prefix == "") || (this.namespaceURI == ""))
							nodeValue = conf.getNodeViaPath(this.xPath);
						else 
							nodeValue = conf.getNodeViaPath(this.xPath, this.prefix, this.namespaceURI);
						if ((nodeValue != null) && (nodeValue.equalsIgnoreCase("yes")))
							continue;
					} catch (Exception e) {
						MP2Exception mp2 = new MP2Exception();
						mp2.setMessage("Error Received When Getting Item 'No' using XPATH.");
						System.err.println(mp2.sendMessage());
						e.printStackTrace();
						throw mp2;
					}
				}
			} catch (IOException e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage("Error Received When Getting XML File from Metadata.");
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}	//write into the tempxml			
			try {
				proxml.setXml(TempXML);
			} catch (Exception e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage("Error Received When Setting XML File.");
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}			
			try {
				proxml.setXsl(Stylesheet);
			} catch (Exception e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage("Error Received When Setting XSL File.");
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}
			try {
				ProcessorOutput = proxml.xmlProcessor(TempOutFile);
			} catch (Exception e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage(MP2Exception.UsingXMLProcessErr);
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}
			try {
				this.writeResultIn(ProcessorOutput);
			} catch (IOException e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage("Error Received When Writing Result Out.");
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}
			proxml.reset();
		}
		return OutputFile;
	} 
}

public class CitationFactory {
	
	protected String TempDir = "";
//	private String TempFile = "";
	protected String ConfFile = "";
//	private String WebRoot  = "";
	protected String Stylesheet = "";
	protected String OutputFile = "";
	protected String Suffix = "";
	protected String MetaData = "";
	protected String Fedora = "";
	protected String Header = "";
	protected String Feet = "";
	protected String TempXML = "";
	protected String TempOutFile = "";
	protected String ProcessorOutput = "";
	
	public void setTempDirectory(String path) {
		TempDir = path;
	}
	
	public void setTempFile(String path) {
		//TempFile = path;
	}
	
	public void setConfFile(String path) {
		ConfFile = path;
	}
	
	public void setWebRoot(String path) {
		//WebRoot = path;
	}
	
	public void setStyleSheet(String path) {
		Stylesheet = path;
	}
	
	public void setOutputFile(String path) {
		OutputFile = path;
	}
	
	public void setFileSuffix(String suffix) {
		Suffix = suffix;
	}
	
	public void setMetaData(String metadata) {
		this.MetaData = metadata;
	}
	
	public void setFedora(String fedora) {
		this.Fedora = fedora;
	}
	
	public void addHeader(String head) {
		Header = head;
	}
	
	public void addFeet(String feet) {
		Feet = feet;
	}
	
	protected void readFromConfig() throws ParserConfigurationException, SAXException, IOException {
		String rootTag 			= "module";
		String identifier 		= "name";
		String pointer	  		= "citation";		
		Configuration cf = new Configuration(ConfFile, 
											 rootTag,
											 identifier,
											 pointer);		
		String stops[] = {"metadata", "fedora"};
		String results[] = cf.readFromConfig(stops);
		MetaData = results[0];
		Fedora = results[1];
	}
	/*
	private void readFromConfig() {
		String rootTag 			= "module";
		String identifier 		= "name";
		String pointer	  		= "citation";	
		String stopOne	  		= "metadata";
		String stopTwo	  		= "fedora";		
		
		MetaData = "DC";
		Fedora = "http://strongbow.nun.unsw.edu.au/fedora/get/";		
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(new File(ConfFile));
			doc.getDocumentElement().normalize();  
			NodeList nodes = doc.getElementsByTagName(rootTag);	          
			for (int i = 0; i < nodes.getLength(); i++) {
				Node node = nodes.item(i);
				if (node.getNodeType() == Node.ELEMENT_NODE) {
					Element element = (Element) node;
					NodeList id	  = element.getElementsByTagName(identifier);
					if (((((Node) id.item(0)).getChildNodes()).item(0).getNodeValue().trim()).equalsIgnoreCase(pointer)) {
						id = element.getElementsByTagName(stopOne);
						MetaData = (((Node) id.item(0)).getChildNodes()).item(0).getNodeValue().trim();
						id = element.getElementsByTagName(stopTwo);
						Fedora	 = (((Node) id.item(0)).getChildNodes()).item(0).getNodeValue().trim();
						return;
					}
				}
			}
		} catch (Exception e) {}		
	}
	*/
	
	public void cleanTempFile(String suffix) {
		String fileLists[] = new File (TempDir).list();
		if (fileLists == null)
			return;
		for (int i = 0; i < fileLists.length; i++) {
			if (fileLists[i].endsWith("." + suffix)) {				
				new File(TempDir + fileLists[i]).delete();
			}
		}
	}
	
	public String createTempFile(String mask, String suffix) throws IOException {
	   File temp = File.createTempFile(mask, "." + Suffix + "."+suffix, new File(TempDir));
	   return temp.getAbsolutePath();
	}
	
	protected void createOutputFile() throws IOException {
		OutputFile = (File.createTempFile(""+System.currentTimeMillis(), 
											  "." + Suffix, 
											  new File(TempDir))).getAbsolutePath();		
	}
	
	protected void getXMLFile(String pid, String file) throws IOException {
		// get file from fedora, then write out to temp xml file.
		String url = Fedora+pid+"/"+MetaData;
		String utf8 = "UTF8";
		URL conn = new URL(url);
		Object obj = conn.getContent();			
		//InputStreamReader temp = ;		
		InputStreamReader reader  = new InputStreamReader((InputStream) obj, utf8);
		FileOutputStream fos = new FileOutputStream(file);
		int chr;
		String output = "";
		while ((chr = (reader.read())) != -1) {					
			output += (char) chr;
		}
		Writer writer = new OutputStreamWriter(fos, utf8);
		writer.write(output.trim());
		/*
		 * previous code generated charset error.
		InputStreamReader reader  = new InputStreamReader((InputStream) obj, utf8);
		FileWriter writer	   = new FileWriter(file);	// path is ab				
		int chr;
		String output = "";
		while ((chr = (reader.read())) != -1) {					
			output += (char) chr;
		}
		writer.write(output.trim());
		System.out.println("############# encode name is " + writer.getEncoding());
		*/
		reader.close();
		//writer.flush();
		writer.close();		
	}
	
	protected void writeResultIn(String inputUrl) throws IOException {
		
		FileWriter writer = new FileWriter(OutputFile, true);
		FileReader reader = new FileReader(inputUrl);
		BufferedReader br = new BufferedReader(reader);
		PrintWriter bw    = new PrintWriter(writer);
		String line = "";
		
		bw.print(Header);							
		while((line = br.readLine()) != null)
			bw.println(line);
		bw.print(Feet);
			
		bw.println();				
		br.close();
		bw.flush();
		bw.close();
		reader.close();
		//writer.flush();
		writer.close();
	}
	
	private void useBackupFile(String file) throws IOException {
		String info = "<info>This is a backup file, since the metadata xml file is demaged </info>";
		String utf8 = "UTF8";
		
		Writer writer = new OutputStreamWriter(new FileOutputStream(file), utf8);
		writer.write(info.trim());
		writer.close();
	}
		
	public String produce(String[] objIds) throws MP2Exception {
		//if (OutputFile.equals(""))			
		try {
			this.createOutputFile();
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.UnableToCreateOutputFileErr);
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
			throw mp2;
		}
		/*
		try {
			this.readFromConfig();
		} catch (Exception e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.ReadingConfFileErr);
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
			throw mp2;
		}
		*/
		XMLProcessor proxml = new XMLProcessor();
		try {
			TempXML = this.createTempFile(""+System.currentTimeMillis(), "xml");
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.CreateTempFileErr);
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
			throw mp2;
		}
		
		try {
			TempOutFile = this.createTempFile(""+System.currentTimeMillis(), Suffix);
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.CreateTempFileErr);
			System.err.println(mp2.sendMessage());
			e.printStackTrace();
			throw mp2;
		}
		for (int i = 0; i < Array.getLength(objIds); i++) {			
			try {
				this.getXMLFile((String) objIds[i], TempXML);
			} catch (IOException e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage("Error Received When Getting XML File from Metadata.");
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				try {
					this.useBackupFile(TempXML);
				} catch (IOException e1) {
					MP2Exception mp2a = new MP2Exception();
					mp2.setMessage("Error Received When Getting XML File from Metadata.");
					System.err.println(mp2a.sendMessage());
					e.printStackTrace();
					throw mp2a;
				}
			}	//write into the tempxml			
			try {
				proxml.setXml(TempXML);
			} catch (Exception e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage("Error Received When Setting XML File.");
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}			
			try {
				proxml.setXsl(Stylesheet);
			} catch (Exception e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage("Error Received When Setting XSL File.");
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}
			try {
				ProcessorOutput = proxml.xmlProcessor(TempOutFile);
			} catch (Exception e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage(MP2Exception.UsingXMLProcessErr);
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}
			try {
				this.writeResultIn(ProcessorOutput);
			} catch (IOException e) {
				MP2Exception mp2 = new MP2Exception();
				mp2.setMessage("Error Received When Writing Result Out.");
				System.err.println(mp2.sendMessage());
				e.printStackTrace();
				throw mp2;
			}
			proxml.reset();
		}
		return OutputFile;
	}
		
	public void reset() {
		(new File(TempXML)).delete();
		(new File(TempOutFile)).delete();
		(new File(ProcessorOutput)).delete();
		(new File(OutputFile)).delete();
	}
}
